home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 June / EnigmA AMIGA RUN 08 (1996)(G.R. Edizioni)(IT)[!][issue 1996-06][EARSAN CD VII].iso / earcd / dbase / kf2ex.lha / KingFisher-Distribution / Developer / kf-api.doc < prev    next >
Text File  |  1995-09-06  |  19KB  |  523 lines

  1.  
  2.          KingFisher Database Server (KFServer)
  3.         Application Programming Interface (API)
  4.           Copyright © 1993,1994,1995 Udo K. Schuermann
  5.               All rights reserved
  6.  
  7.  
  8.  
  9. ---------------------------------------------------------------------------
  10. INTRODUCTION
  11. ---------------------------------------------------------------------------
  12.  
  13. The KFServer's API is based on the Amiga's Exec messages.  This is a very
  14. efficient means of transporting potentially enormous amounts of information
  15. between multiple tasks.  The only way for a client application to talk to
  16. the KFServer is by sending messages to the KFServer and waiting for these
  17. to be returned.
  18.  
  19. All the gory details of this process are handled for you by the "kf-api.c"
  20. file, providing you with simple functions to setup messages, fill the
  21. parameter fields, send the message, wait for a reply from the KFServer, and
  22. then return you the necessary results.
  23.     The "kf-api.c" functions were developed using SAS/C 6.55 but should
  24. be easily compiled with other compilers, too.
  25.  
  26.  
  27.  
  28. ---------------------------------------------------------------------------
  29. GETTING STARTED
  30. ---------------------------------------------------------------------------
  31.  
  32. The first thing you should do is compile "kf-api.c" to produce "kf-api.o"
  33. (i.e. don't link this file with anything; you'll use the functions in the
  34. object (.o) file later to link with your project.)  Once you have this file
  35. compiled you are ready to begin your project!
  36.  
  37. The basic outline of a KFServer Client Application is this:
  38.  
  39.     Handle = KFLogin( "Identifier" )
  40.     IF (Handle = NULL) THEN EXIT( "Server Not Running" )
  41.  
  42.     REPEAT
  43.       Issue command
  44.       IF Successful THEN ECHO Results
  45.     UNTIL Finished
  46.  
  47.     KFLogout( Handle )
  48.  
  49. 1. An application must always login to the server at least once.  The
  50.    "Handle" is the identifier passed to every API function, to identify
  51.    this "connection" to the server.  If you examine the "ReOrder.c" tool,
  52.    you will notice that TWO (2) handles are obtained, one for the input
  53.    database, and one for the output database.
  54.     There is no limit (except with the unregistered version) to the
  55.    number of handles your software may obtain.  Each such handle is
  56.    associated with a database and maintains its own, distinct set of
  57.    parameters.  This provides simultaneous access to multiple databases.
  58.  
  59. 2. The KFServer is a single-threaded application, which means it processes
  60.    each request as it comes in and goes on to the next request only when
  61.    the previous one has completed and has been returned to the client.
  62.    This means that certain lengthy operations (such as a database reindex
  63.    operation) could tie up the server for several minutes, thereby blocking
  64.    all access by other clients.
  65.     To somewhat lessen the impact of this potentially very frustrating
  66.    blockage, these lengthy operations return to the caller periodically
  67.    with the implication that the function is called again at once until the
  68.    KFServer finally returns with an "all done," whereupon the function is
  69.    completed.
  70.     These interruptions provide brief pauses during which other clients
  71.    may get a few requests processed.  It is also recommended that a client
  72.    lower its priority by one before embarking on such a lengthy procedure.
  73.    This can greatly improve response time for other clients, should there
  74.    be any!
  75.     The "kf-api.c" function for reindexing, for example, takes care of
  76.    the repeated calling, so there is no need for you to directly concern
  77.    yourself with this aspect unless you should wonder why your other client
  78.    software is slowing down dramatically during a reindexing operation.
  79.  
  80. 3. Always call KFLogout() on a handle you have obtained.  If you are using
  81.    SAS/C 6.50+ and the kf-api.c file has the #define USEAUTO enabled (which
  82.    it is, by default) then the kf-api.c will automatically clear all open
  83.    handles for you when you exit, but it is not recommended to rely on
  84.    this.
  85.  
  86.  
  87.  
  88. ---------------------------------------------------------------------------
  89. EXAMPLE OF USING THE KF-API.C
  90. ---------------------------------------------------------------------------
  91.  
  92. Here is a very small application you can play with:
  93.  
  94.     #include <stdio.h>
  95.     #include "kf-api.h"
  96.     main() {
  97.       struct KFMsg *HANDLE = KFLogin("My Mini Project");
  98.       if( HANDLE ) {
  99.         unsigned long MaxClients;
  100.         char *DefaultDB;
  101.  
  102.         MaxClients = KFMaxClients( HANDLE );
  103.         printf("This KFServer supports %ld clients,\n",MaxClients);
  104.  
  105.         DefaultDB = KFCurDatabaseName( HANDLE );
  106.         printf("and serves \"%s\" as the default database.\n",DefaultDB);
  107.         KFLogout( HANDLE );
  108.         /* at this time HANDLE is invalid */
  109.       } else
  110.         printf("Cannot login!\n");
  111.     } /* main() */
  112.  
  113. This application makes use of the following API functions:
  114.  
  115.     KFLogin()
  116.     KFLogout()
  117.     KFMaxClients()
  118.     KFCurDatabaseName()
  119.  
  120. These functions are described in detail in the section below.
  121.  
  122.  
  123.  
  124. ---------------------------------------------------------------------------
  125. FUNCTIONS IN THE API:
  126. ---------------------------------------------------------------------------
  127.  
  128. struct KFMsg *KFLogin( char *Identifier );
  129.  
  130.     This should almost always be the first function you call.  It
  131.     returns you the handle which you use in all subsequent calls.  The
  132.     parameter to this function should be some meaningful identification
  133.     and may even be NULL.  It is highly recommended to somehow identify
  134.     your application, as in the example above.  The KFServer does NOT
  135.     make a copy of this string, so the address must continue to live as
  136.     long as the handle is active.
  137.  
  138.     If the function returns NULL, then login failed.  There is more
  139.     than one reason for this.  As there is no message with error field
  140.     that is returned by this function, examine (but do not modify!) the
  141.     variables
  142.  
  143.         UWORD AsyncErr
  144.     and
  145.         char *AsyncMsg
  146.  
  147.     for an error code and some additional explanation.  The most likely
  148.     causes of a KFLogin() call failing is that either the KFServer is
  149.     out of handles (never the case with the registered version) or the
  150.     KFServer is not running and could not be started successfully.
  151.  
  152.  
  153.  
  154. BOOL KFLogout( struct KFMsg *Msg );
  155.  
  156.     Always call this function with every handle obtained through the
  157.     KFLogin() call.  It is legal to call this function with a NULL
  158.     handle, but the function will return FALSE in that case.
  159.  
  160.     The function returns TRUE if the logout succeeded.  In either case,
  161.     the handle is invalid after this call.
  162.  
  163.  
  164.  
  165. BOOL KFStatus( struct KFMsg *Msg );
  166.  
  167.     Obtains information about the currently attached client, including
  168.     the current database in use, the current record position in the
  169.     database, the version of the running server, etc.  This information
  170.     is returned in the handle's .BParam field.
  171.  
  172.     EX:    if( KFStatus( HANDLE ) )
  173.           printf("%s\n",HANDLE->BParam);
  174.  
  175.     NOTE:    In a future version, this function will not require a prior
  176.         KFLogin() and may be used to obtain some simple information
  177.         about the KFServer (which will be started if not running.)
  178.  
  179.  
  180.  
  181. ULONG KFMaxClients( struct KFMsg *Msg );
  182.  
  183.     Obtains the maximum number of clients that the currently running
  184.     KFServer supports.  Depending on how many handles have already been
  185.     handed out by the KFServer to various clients, the actual number of
  186.     available handles may be less than the maximum.  This should be of
  187.     concern only with unregistered versions.
  188.  
  189.     EX:    ULONG MaxClients = KFMaxClients( HANDLE );
  190.  
  191.     NOTE:    It is LEGAL to call KFMaxClients() with a NULL handle!
  192.         This will actually create a temporary handle and call the
  193.         KFServer with that.  If the KFServer is configured with the
  194.         "keep-running=no" parameter, however, the KFServer will
  195.         NOT, in this case, terminate again, but remain operational
  196.         with 0 clients attached.  Auto termination of the KFServer
  197.         functions only during an actual logout procedure.
  198.  
  199.  
  200.  
  201. ULONG KFCurFish( struct KFMsg *Msg );
  202.  
  203.     Obtains the current position in the database which is a number 1 or
  204.     greater.  If this function returns 0, then the database is empty
  205.     and no record or record-specific data may be obtained from it.
  206.  
  207.     EX:    ULONG CurFish = KFCurFish( HANDLE );
  208.         if( CurFish == 0 )
  209.           printf("We have no data!\n");
  210.         else
  211.           printf("Record #%ld is the current one.\n",CurFish);
  212.  
  213.     NOTE:    The .FParam field is also filled with the current flags
  214.         (see KFCurFlags() function below.)
  215.  
  216.  
  217.  
  218. UWORD KFCurFlags( struct KFMsg *Msg );
  219.  
  220.     Obtains the flags of the current record in the database.  Eight of
  221.     these flags are pre-defined, while another eight are application or
  222.     user-specific.
  223.  
  224.         UWORD CurFlags = KFCurFlags( HANDLE );
  225.         printf("System flags: %02x, User flags: %02x\n",
  226.             CurFlags >> 8,
  227.             CurFlags & 0x0f);
  228.  
  229.     NOTE:    The KFCurFish() command (see above) provides the current
  230.         flags as a sideeffect in the handle's .FParam field.
  231.  
  232.  
  233.  
  234. ULONG KFCurDisk( struct KFMsg *Msg );
  235.  
  236.     Obtains the current disk number with which the current record is
  237.     associated.  Note, that a single-volume software collection, such
  238.     as found on a CD-ROM, is likely to be organized as a single disk,
  239.     wherefore the disk number is always 1.
  240.  
  241.  
  242.  
  243. char *KFCurDatabaseName( struct KFMsg *Msg );
  244.  
  245.     Obtains the .kfdb filename of the current database.
  246.  
  247.     NOTE:    The value returned is actually the same pointer as the
  248.         handle's .Buffer, wherefore the value will not survive the
  249.         next use of the handle when passed to the KFServer again.
  250.         If you require this value, then strcpy() it to a different
  251.         buffer!
  252.  
  253.  
  254.  
  255. ULONG KFCurDatabaseSize( struct KFMsg *Msg );
  256.  
  257.     Returns the number of records in the current database.  If the
  258.     function returns 0, then the database is empty.
  259.  
  260.  
  261.  
  262. BOOL KFSelectFish( struct KFMsg *Msg, ULONG FishNumber );
  263.  
  264.     Selects a different record in the database for future operations.
  265.     The record (FishNumber) given must be 1 or greater, and must not
  266.     exceed the total number of records in the database (as returned by
  267.     a call to KFCurDatabaseSize().)
  268.  
  269.  
  270.  
  271. ULONG KFNextVersion( struct KFMsg *Msg );
  272. ULONG KFPrevVersion( struct KFMsg *Msg );
  273.  
  274.     Returns the record number of the next/previous version as stored in
  275.     the current database's index.  If this function returns 0, then no
  276.     next/previous version is known.
  277.  
  278.  
  279.  
  280. BOOL KFListDatabases( struct KFMsg *Msg );
  281.  
  282.     This call returns a pointer to the handle's .Buffer where the
  283.     KFServer has stored a list of all known .kfdb files, along with the
  284.     long, human-readable descriptions found within these.  The format
  285.     of the buffer is:
  286.  
  287.         Descriptive database name
  288.         \1
  289.         .kfdb name
  290.         \n
  291.  
  292.     This is repeated for each existing .kfdb file and the buffer is
  293.     then terminated with a \0.  Notice that \1 is an ASCII 01 (^A)
  294.     symbol, and \n is a newline.
  295.  
  296.     Here is an example without the linebreaks used above to make the
  297.     components stand out more distinctly:
  298.  
  299.         Fresh Fish® Database\1FreshFish.kfdb\n
  300.         Original Fish Disks\11000Fish.kfdb\n
  301.         \0
  302.  
  303.  
  304.  
  305. BOOL KFSelectDatabase( struct KFMsg *Msg, char *Filename );
  306.  
  307.     Ask the KFServer to close the current database and switch to the
  308.     new database whose name (a .kfdb file) is given by the Filename
  309.     parameter.  The 1st record in the database becomes the current
  310.     record.  Clients may wish to restore an old, saved position with a
  311.     KFSelectFish() call or directly load a record with a KFGetFish()
  312.     call.
  313.  
  314.     The command returns FALSE if the new database could not be opened,
  315.     in which case the current database is not closed.  If the function
  316.     returns TRUE, the .BParam contains a bitmask to indicate the R/W
  317.     status of various database components.  If the entire value is 0,
  318.         (equal to a boolean FALSE) then no portion of the database can be
  319.         modified.  AND'ing the value with the following gives details on
  320.     each component:
  321.         x AND 1        The main database index
  322.         x AND 2        The quick index
  323.         x AND 4        The database records
  324.     If the database is not writable, any additions to it, or changes
  325.     to the index (i.e. flags) can, and most likely will, cause error
  326.     messages from the server when the database is closed.
  327.  
  328.     NOTE:    The Filename must be terminated either by a \0 or \n.
  329.         This makes it easier to point directly at a name in the
  330.         .Buffer (see KFListDatabases() command, above.)
  331.     NOTE:   In previous versions the .BParam value was a simple
  332.         boolean to indicate read/write status of the entire
  333.         database based solely on the main index, which was not
  334.         always correct, especially when only the main index
  335.         resided on writable medium.
  336.  
  337.  
  338.  
  339. BOOL KFGetFish( struct KFMsg *Msg, ULONG FishNumber );
  340.  
  341.     Retrieves a specific record from the current database.  If the
  342.     FishNumber is 0 (rather than a valid record number 1 or greater)
  343.     then the current record is retrieved, whichever that may be.
  344.  
  345.     NOTE:    The .BParam field returns the actual record number
  346.             retrieved (useful when called with a record of 0)
  347.         The .DParam field returns the disk with which this record
  348.             is associated
  349.         The .FParam field returns the record's associated flags
  350.             (see the KFCurFlags() command)
  351.         The .FInfo field returns situational information on this
  352.             record, indicating if previous or next versions
  353.             exist, or if this is the first or last record or
  354.             disk in the database.  This field represents a mask
  355.             of bits, which are defined in the kf.h file.
  356.  
  357.  
  358.  
  359. BOOL KFSetFlag( struct KFMsg *Msg, UWORD Mask );
  360. BOOL KFClrFlag( struct KFMsg *Msg, UWORD Mask );
  361.  
  362.     Sets/clears flags in the indicated Mask.  A Mask of 0xffff would
  363.     set/clear all flags.  A Mask of 0x0000 has no effect at all.  You
  364.     should not call this function if the call to KFSelectDatabase()
  365.     returned a 0 in the .BParam field, indicating that the database
  366.     cannot be modified.
  367.  
  368.  
  369.  
  370. BOOL KFFindFlag( struct KFMsg *Msg, BOOL Forward, UWORD MatchMask, UWORD AvoidMask );
  371.  
  372.     Starting with the current record, the KFServer will make current
  373.     the next or previous record matching the given masks.  If
  374.     successful, the function returns TRUE and the new record number is
  375.     returned in the .BParam field.
  376.  
  377.     An AvoidMask of 0xffff will NEVER produce a match (as all records
  378.     with any flag are avoided), while a MatchMask of 0x0000 will
  379.     likewise NEVER produce a match.
  380.  
  381.     The Forward variable determines the direction in which the search
  382.     is performed.  The KFServer can search thousands of records in a
  383.     fraction of a second.
  384.  
  385.  
  386.  
  387. BOOL KFGetDisk( struct KFMsg *Msg, ULONG DiskNumber );
  388.  
  389.     Retrieves the first record associated with the indicated disk,
  390.     provided this disk exists (in which case the function returns TRUE)
  391.     and an implicit KFGetFish() call has been performed (see above.)
  392.  
  393.  
  394.  
  395. BOOL KFNextFish( struct KFMsg *Msg );
  396. BOOL KFPrevFish( struct KFMsg *Msg );
  397.  
  398.     Moves to the next/previous record in the database, returning TRUE
  399.     if such a record existed.  No retrieval of data is performed.
  400.  
  401.  
  402.  
  403. BOOL KFParseFile( struct KFMsg *Msg, char *Filename );
  404. BOOL KFEndParsing( struct KFMsg *Msg );
  405.  
  406.     KFParseFile() is called both to begin and to continue parsing a
  407.     file for records in the Product Info Specification format.  Each
  408.     time the function returns either TRUE or FALSE.  If TRUE, the
  409.     .Buffer contains a record extracted from the file, which may be
  410.     passed to the KFAddFish() function if so desired.
  411.  
  412.     Once this function returns FALSE, or the .Error field contains
  413.     kfeNOMORE, the file has been completely parsed for all records.
  414.     Only if you wish to terminate parsing before the file has been
  415.     completely scanned, may you call KFEndParsing().
  416.  
  417.     EX:    BOOL HaveAdded = FALSE;
  418.         for(;;) {
  419.           if( KFParseFile( HANDLE, "myfile" ) ) {
  420.             printf("%s\n\n***** Add this record? (Y/N/Q) ",
  421.                 HANDLE->Buffer);
  422.             /* get Yes/No/Quit response */
  423.             if( Yes )
  424.               if( KFAddFish( HANDLE, 1, 0x0000, -1, -1 ))
  425.             HaveAdded = TRUE;
  426.               else {
  427.             printf("Cannot add to the database!\n");
  428.             break;
  429.               }
  430.             else
  431.             if( No )
  432.               continue;
  433.             else
  434.             if( Quit ) {
  435.               break;
  436.             }
  437.                   } else {
  438.                     HaveAdded = FALSE; /* KFServer knows it's done */
  439.                     break;
  440.                   }
  441.         } /* for */
  442.         if( HaveAdded )
  443.           KFEndAdding( HANDLE );
  444.  
  445.  
  446.  
  447. BOOL KFAddFish( struct KFMsg *Msg, UWORD Disk, UWORD Flags, LONG PrevVersion, LONG NextVersion );
  448. BOOL KFEndAdding( struct KFMsg *Msg );
  449.  
  450.     When KFAddFish() is first called, it attempts to lock the current
  451.     database for exclusive access.  If more than one handle to this
  452.     database has been given out (even if both are in your "possession")
  453.     the call will fail.
  454.  
  455.     Once you have added all the records you wish to add, call the
  456.     KFEndAdding() function to release the database again to everyone
  457.     else.
  458.  
  459.     For an example of this function, see the source code example above.
  460.  
  461.  
  462.  
  463. BOOL KFReindex( struct KFMsg *Msg );
  464.  
  465.     This function attempts to lock the current database for exclusive
  466.     access.  If it succeeds, it will proceed to reindex the database,
  467.     thereby rebuilding all related index files based solely on the data
  468.     found in the database files.
  469.  
  470.     Once the function returns, the database has been released again and
  471.     the index is up to date.  Notice that this function may require
  472.     much time to perform its duty, during which other database clients
  473.     may experience EXTREME drop in performance.  For this reason, it is
  474.     STRONGLY RECOMMENDED to lower your process priority before calling
  475.     this function, and raise it again once completed.
  476.  
  477.     Previously mentioned problems with the reindexing operation have
  478.     been corrected, to the best of my knowledge and experience.
  479.  
  480.  
  481. ---------------------------------------------------------------------------
  482. HINTS AND TIPS
  483. ---------------------------------------------------------------------------
  484.  
  485. 1. Use the functions provided by the API as much as possible.  It is LEGAL
  486.    to access the fields of the handle, so long as their use is documented
  487.    here.  Do not rely on apparently reliable behavior if no mention is made
  488.    of it here.  If you must know, ask me.  It may always be an omission.
  489.    If you need something added, let me know and I will see what I can do.
  490.  
  491. 2. You may modify the KFAPIServerName[128] array to provide a different
  492.    name of the KFServer binary, perhaps with a full path added.  This is
  493.    the file which the API attempts to start when the KFServer's message
  494.    port cannot be located.
  495.     KingFisher copies the value of the SERVERNAME tooltype to this
  496.    variable.
  497.  
  498.    If you wish to suppress startup messages and console windows for the
  499.    cleanest look, set the KFAPISilentRun to TRUE.
  500.     KingFisher does this if it finds the NOOUTPUT tooltype.
  501.  
  502.    Never EVER rely on anything else in the kf-api.c file, as nothing else
  503.    will be guaranteed and behavior may dramatically change.
  504.  
  505. 3. If so desired, you may use the CallServer() function, which expects a
  506.    fully initialized handle.  The use of CallServer() is documented in the
  507.    "kf-api.c" by itself and all the functions that use it.
  508.  
  509. 4. If you experience problems, please let me know.  The more detail you can
  510.    give, the more likely it is that I can help you.
  511.  
  512. 5. While the file above may not always be up to date, you can get more
  513.    detail (although fewer examples) on the exact message port interface
  514.    from the kf.h file.
  515.  
  516.  
  517. Enjoy!
  518.  
  519.  ._.  Udo Schuermann             Snail mail:  7022 Hanover Parkway, Apt. C2
  520.  ( )  walrus@wam.umd.edu                      Greenbelt, MD 20770-2049
  521.  
  522. #EOT
  523.